package com.xiashitech.agent.utils;

import com.xiashitech.agent.config.StartConfig;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarLoadUtil {

    /**
     * 加载jar:1、从文件夹中加载所有jar;2、从启动包中加载jar(jar文件在启动包根目录下)
     * @param path
     */
    public static void loadJar(String path) {
        File libPathFile = new File(path);
        Method method = null;
        boolean accessible = false;
        try {
            method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            accessible = method.isAccessible();
            if (accessible == false) {
                method.setAccessible(true);
            }
            URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
            if(libPathFile.isDirectory()) {
                File[] jarFiles = libPathFile.listFiles(new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                        return name.endsWith(".jar") || name.endsWith(".zip");
                    }
                });
                if (jarFiles != null) {
                    for (File file : jarFiles) {
                        URL url = file.toURI().toURL();
                        Long isExist = Arrays.stream(classLoader.getURLs()).filter(urlPath -> {
                            String prePath = "pre";
                            if(urlPath.getPath().lastIndexOf("/") +1 < urlPath.getPath().length()) {
                                prePath = urlPath.getPath().substring(urlPath.getPath().lastIndexOf("/"));
                            }
                            String afterPath = "after";
                            if(url.getPath().lastIndexOf("/") +1 < url.getPath().length()) {
                                afterPath = url.getPath().substring(url.getPath().lastIndexOf("/"));
                            }
                            if(prePath.equals(afterPath)) {
                                return true;
                            } else {
                                return false;
                            }
                        }).count();
                        if(isExist == 0L) {
                            method.invoke(classLoader, url);
                        }
                    }
                }
            } else if(libPathFile.isFile() && libPathFile.getName().endsWith(".jar")) {
                try {
                    JarFile jarFile = new JarFile(libPathFile);
                    Enumeration<JarEntry> entries = jarFile.entries();
                    while (entries.hasMoreElements()){
                        JarEntry entry = entries.nextElement();
                        if(entry.getName().endsWith(".jar")){
                            Long isExist = Arrays.stream(classLoader.getURLs()).filter(urlPath -> urlPath.getPath().endsWith(entry.getName())).count();
                            if(isExist == 0L) {
                                try {
                                    File tempPath;
                                    if(System.getProperty("os.name") != null && System.getProperty("os.name").startsWith("Windows")) {
                                        tempPath = new File(System.getProperty("java.io.tmpdir") + "agentcache" + File.separator);
                                    } else {
                                        tempPath = new File(System.getProperty("java.io.tmpdir") + File.separator + "agentcache" + File.separator);
                                    }
                                    if(!tempPath.exists()) {
                                        tempPath.mkdirs();
                                    }
                                    File tempCacheFile;
                                    if(System.getProperty("os.name") != null && System.getProperty("os.name").startsWith("Windows")) {
                                        tempCacheFile = new File(System.getProperty("java.io.tmpdir") + "agentcache" + File.separator + entry.getName());
                                    } else {
                                        tempCacheFile = new File(System.getProperty("java.io.tmpdir") + File.separator + "agentcache" + File.separator + entry.getName());
                                    }

                                    if(!tempCacheFile.exists()) {
                                        InputStream inputStream = jarFile.getInputStream(entry);
                                        FileOutputStream outputStream = new FileOutputStream(tempCacheFile);
                                        while (inputStream.available() > 0) {
                                            outputStream.write(inputStream.read());
                                        }
                                        inputStream.close();
                                        outputStream.close();
                                    }
                                    method.invoke(classLoader, tempCacheFile.toURI().toURL());
                                } catch (Exception e) {
                                    StartConfig.throwableStackPrinter(e);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    StartConfig.throwableStackPrinter(e);
                }
            }
        } catch (Exception e) {
            StartConfig.throwableStackPrinter(e);
        } finally {
            if(method != null) {
                method.setAccessible(accessible);
            }
        }
    }
}
